# 检查编译器是否为 GCC 且版本大于 4.1.2
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.1.2)
    # -Werror=* 选项在 GCC 4.1.2 之后引入
    # 该选项将严格别名警告视为错误
    add_compile_options("-Werror=strict-aliasing")
endif()

# 包含 CMake 模块，用于检查头文件、类型大小、结构体成员和符号是否存在
include(CheckIncludeFileCXX)
include(CheckTypeSize)
include(CheckStructHasMember)
include(CheckCXXSymbolExists)

# 检查是否存在 clocale 头文件
check_include_file_cxx(clocale HAVE_CLOCALE)
# 检查 clocale 头文件中是否存在 localeconv 符号
check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV)

# 设置额外的包含文件，用于后续的检查
set(CMAKE_EXTRA_INCLUDE_FILES clocale)
# 检查 lconv 类型的大小
check_type_size(lconv LCONV_SIZE LANGUAGE CXX)
# 清除额外的包含文件设置
unset(CMAKE_EXTRA_INCLUDE_FILES)
# 检查 lconv 结构体中是否存在 decimal_point 成员
check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX)

# 若缺少必要的本地化功能支持
if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV))
    # 输出警告信息
    message(WARNING "Locale functionality is not supported")
    if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
        # 使用 CMake 3.12 及以上版本的新语法定义宏
        add_compile_definitions(JSONCPP_NO_LOCALE_SUPPORT)
    else()
        # 使用旧语法定义宏
        add_definitions(-DJSONCPP_NO_LOCALE_SUPPORT)
    endif()
endif()

# 设置 JsonCpp 头文件的包含目录
set(JSONCPP_INCLUDE_DIR ../../include)

# 定义公共头文件列表
set(PUBLIC_HEADERS
    ${JSONCPP_INCLUDE_DIR}/json/config.h
    ${JSONCPP_INCLUDE_DIR}/json/forwards.h
    ${JSONCPP_INCLUDE_DIR}/json/json_features.h
    ${JSONCPP_INCLUDE_DIR}/json/value.h
    ${JSONCPP_INCLUDE_DIR}/json/reader.h
    ${JSONCPP_INCLUDE_DIR}/json/version.h
    ${JSONCPP_INCLUDE_DIR}/json/writer.h
    ${JSONCPP_INCLUDE_DIR}/json/assertions.h
)

# 在 IDE 中为公共头文件创建一个名为 "Public API" 的源文件组
source_group("Public API" FILES ${PUBLIC_HEADERS})

# 定义 JsonCpp 源文件列表
set(JSONCPP_SOURCES
    json_tool.h
    json_reader.cpp
    json_valueiterator.inl
    json_value.cpp
    json_writer.cpp
)

# 安装此目标的相关指令
if(JSONCPP_WITH_CMAKE_PACKAGE)
    # 若启用了生成并安装 CMake 包文件的选项，设置导出目标
    set(INSTALL_EXPORT EXPORT jsoncpp)
else()
    # 否则，清空导出目标设置
    set(INSTALL_EXPORT)
endif()

# 指定编译给定目标时所需的编译器特性
# 完整的特性列表可参考 https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html
list(APPEND REQUIRED_FEATURES
        cxx_std_11 # 编译器支持 C++ 11 标准
        #MSVC 1900 cxx_alignas # 对齐控制 alignas，定义于 N2341
        #MSVC 1900 cxx_alignof # 对齐控制 alignof，定义于 N2341
        #MSVC 1900 cxx_attributes # 通用属性，定义于 N2761
        cxx_auto_type # 自动类型推导，定义于 N1984
        #MSVC 1900 cxx_constexpr # 常量表达式，定义于 N2235
        cxx_decltype # Decltype，定义于 N2343
        cxx_default_function_template_args # 函数模板的默认模板参数，定义于 DR226
        cxx_defaulted_functions # 默认函数，定义于 N2346
        #MSVC 1900 cxx_defaulted_move_initializers # 默认移动初始化器，定义于 N3053
        cxx_delegating_constructors # 委托构造函数，定义于 N1986
        #MSVC 1900 cxx_deleted_functions # 删除函数，定义于 N2346
        cxx_enum_forward_declarations # 枚举前向声明，定义于 N2764
        cxx_explicit_conversions # 显式转换运算符，定义于 N2437
        cxx_extended_friend_declarations # 扩展友元声明，定义于 N1791
        cxx_extern_templates # 外部模板，定义于 N1987
        cxx_final # 覆盖控制 final 关键字，定义于 N2928、N3206 和 N3272
        #MSVC 1900 cxx_func_identifier # 预定义 __func__ 标识符，定义于 N2340
        #MSVC 1900 cxx_generalized_initializers # 初始化列表，定义于 N2672
        #MSVC 1900 cxx_inheriting_constructors # 继承构造函数，定义于 N2540
        #MSVC 1900 cxx_inline_namespaces # 内联命名空间，定义于 N2535
        cxx_lambdas #  lambda 函数，定义于 N2927
        #MSVC 1900 cxx_local_type_template_args # 局部和未命名类型作为模板参数，定义于 N2657
        cxx_long_long_type # long long 类型，定义于 N1811
        #MSVC 1900 cxx_noexcept # 异常规范，定义于 N3050
        #MSVC 1900 cxx_nonstatic_member_init # 非静态数据成员初始化，定义于 N2756
        cxx_nullptr # 空指针，定义于 N2431
        cxx_override # 覆盖控制 override 关键字，定义于 N2928、N3206 和 N3272
        cxx_range_for # 基于范围的 for 循环，定义于 N2930
        cxx_raw_string_literals # 原始字符串字面量，定义于 N2442
        #MSVC 1900 cxx_reference_qualified_functions # 引用限定函数，定义于 N2439
        cxx_right_angle_brackets # 右尖括号解析，定义于 N1757
        cxx_rvalue_references # 右值引用，定义于 N2118
        #MSVC 1900 cxx_sizeof_member # 非静态数据成员的大小，定义于 N2253
        cxx_static_assert # 静态断言，定义于 N1720
        cxx_strong_enums # 强类型枚举，定义于 N2347
        #MSVC 1900 cxx_thread_local # 线程局部变量，定义于 N2659
        cxx_trailing_return_types # 自动函数返回类型，定义于 N2541
        #MSVC 1900 cxx_unicode_literals # Unicode 字符串字面量，定义于 N2442
        cxx_uniform_initialization # 统一初始化，定义于 N2640
        #MSVC 1900 cxx_unrestricted_unions # 无限制联合，定义于 N2544
        #MSVC 1900 cxx_user_literals # 用户定义字面量，定义于 N2765
        cxx_variadic_macros # 可变参数宏，定义于 N1653
        cxx_variadic_templates # 可变参数模板，定义于 N2242
)

# 若启用了构建共享库的选项
if(BUILD_SHARED_LIBS)
    if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
        # 使用 CMake 3.12 及以上版本的新语法定义宏
        add_compile_definitions(JSON_DLL_BUILD)
    else()
        # 使用旧语法定义宏
        add_definitions(-DJSON_DLL_BUILD)
    endif()

    # 设置共享库的目标名称
    set(SHARED_LIB ${PROJECT_NAME}_lib)
    # 创建共享库目标
    add_library(${SHARED_LIB} SHARED ${PUBLIC_HEADERS} ${JSONCPP_SOURCES})
    # 设置共享库的属性
    set_target_properties(${SHARED_LIB} PROPERTIES
        OUTPUT_NAME jsoncpp  # 输出库的名称
        VERSION ${PROJECT_VERSION}  # 库的版本号
        SOVERSION ${PROJECT_SOVERSION}  # 库的 API 版本号
        POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}  # 是否生成位置无关代码
    )

    # 在 OSX 系统上设置库的运行时搜索路径
    if(APPLE)
        set_target_properties(${SHARED_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.")
    endif()

    # 为共享库设置所需的编译器特性
    target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES})

    # 为共享库设置包含目录
    target_include_directories(${SHARED_LIB} PUBLIC
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>  # 安装后的包含目录
        $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>  # 构建时的包含目录
    )

    # 将共享库添加到 CMake 目标列表中
    list(APPEND CMAKE_TARGETS ${SHARED_LIB})
endif()

# 若启用了构建静态库的选项
if(BUILD_STATIC_LIBS)
    # 设置静态库的目标名称
    set(STATIC_LIB ${PROJECT_NAME}_static)
    # 创建静态库目标
    add_library(${STATIC_LIB} STATIC ${PUBLIC_HEADERS} ${JSONCPP_SOURCES})

    # 避免在 Windows 上与共享导入库名称冲突
    if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS)
        if (MSVC OR ("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC"))
            # 在 MSVC 编译器下添加 _static 后缀
            set(STATIC_SUFFIX "_static")
        else()
            # 其他编译器不添加后缀
            set(STATIC_SUFFIX "")
        endif()
    endif()

    # 设置静态库的属性
    set_target_properties(${STATIC_LIB} PROPERTIES
        OUTPUT_NAME jsoncpp${STATIC_SUFFIX}  # 输出库的名称
        VERSION ${PROJECT_VERSION}  # 库的版本号
    )

    # 在 OSX 系统上设置库的运行时搜索路径
    if(APPLE)
        set_target_properties(${STATIC_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.")
    endif()

    # 为静态库设置所需的编译器特性
    target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES})

    # 为静态库设置包含目录
    target_include_directories(${STATIC_LIB} PUBLIC
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>  # 安装后的包含目录
        $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>  # 构建时的包含目录
    )

    # 将静态库添加到 CMake 目标列表中
    list(APPEND CMAKE_TARGETS ${STATIC_LIB})
endif()

# 若启用了构建对象库的选项
if(BUILD_OBJECT_LIBS)
    # 设置对象库的目标名称
    set(OBJECT_LIB ${PROJECT_NAME}_object)
    # 创建对象库目标
    add_library(${OBJECT_LIB} OBJECT ${PUBLIC_HEADERS} ${JSONCPP_SOURCES})

    # 设置对象库的属性
    set_target_properties(${OBJECT_LIB} PROPERTIES
        OUTPUT_NAME jsoncpp  # 输出库的名称
        VERSION ${PROJECT_VERSION}  # 库的版本号
        SOVERSION ${PROJECT_SOVERSION}  # 库的 API 版本号
        POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}  # 是否生成位置无关代码
    )

    # 在 OSX 系统上设置库的运行时搜索路径
    if(APPLE)
        set_target_properties(${OBJECT_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.")
    endif()

    # 为对象库设置所需的编译器特性
    target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES})

    # 为对象库设置包含目录
    target_include_directories(${OBJECT_LIB} PUBLIC
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>  # 安装后的包含目录
        $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>  # 构建时的包含目录
    )

    # 将对象库添加到 CMake 目标列表中
    list(APPEND CMAKE_TARGETS ${OBJECT_LIB})
endif()

# 安装目标
install(TARGETS ${CMAKE_TARGETS} ${INSTALL_EXPORT}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}  # 可执行文件安装目录
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}  # 共享库安装目录
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}  # 静态库安装目录
    OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR}  # 对象文件安装目录
)

